home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C ++ / Applications / FlyThrough 1.1.2 / src / Source / QD3D General Tools / CQD3DPane.cp < prev    next >
Encoding:
Text File  |  1997-03-17  |  13.6 KB  |  543 lines  |  [TEXT/CWIE]

  1. //
  2. //    CQD3DPane.cp
  3. //
  4. //    class CQD3DPane [abstract]
  5. //    A Pane for rendering a QuickDraw 3D view.
  6. //
  7. //    by James Jennings
  8. //    November 21, 1995
  9. //
  10.  
  11. #include "CQD3DPane.h"
  12. #include "StQ3Disposer.h"
  13. #include "QD3D Debug Macros.h"
  14.  
  15. #include "CDrawContextMaker.h"
  16. #include "CRendererMaker.h"
  17. #include "CCameraMaker.h"
  18. #include "C3Lights.h"
  19.  
  20. #include "CBoxMaker.h"
  21.  
  22. #include <QD3DGeometry.h>
  23. #include <QD3DShader.h>
  24. #include <QD3DCamera.h>
  25. #include <QD3DLight.h>
  26. #include <QD3DGroup.h>
  27. #include <QD3DRenderer.h>
  28. #include <QD3DDrawContext.h>
  29. #include <QD3DMath.h>
  30. #include <QD3DTransform.h>
  31. #include <QD3DAcceleration.h>    // defines kQAVendor_BestChoice
  32.  
  33. Boolean    CQD3DPane::sSawFatalError = false;    // Stop processing when there is a fatal error.
  34. Boolean    CQD3DPane::sNowSubmitting = false;    // Keep submitting loops from being reentrant.
  35.  
  36. CQD3DPane*    CQD3DPane::CreateFromStream(LStream *inStream)
  37. {
  38.     return new CQD3DPane( inStream );
  39. }
  40.  
  41. CQD3DPane::CQD3DPane()
  42.     : mView(0), mModel(0), mInterpolation(0), mBackFacing(0), mFillStyle(0),
  43.       mLights(0), mCamera(0), mDrawContext(0), mRenderer(0), mDefaultAttributes(0)
  44. {    // default constructor
  45.     // Does nothing. QD3D Objects are built when needed.
  46. }
  47.  
  48. CQD3DPane::CQD3DPane(const CQD3DPane &inOriginal) : LPane(inOriginal),
  49.     mView(0), mModel(0), mInterpolation(0), mBackFacing(0), mFillStyle(0),
  50.       mLights(0), mCamera(0), mDrawContext(0), mRenderer(0), mDefaultAttributes(0)
  51. {    // copy constructor
  52.     SignalPStr_("\pcopy constructor needs rewriting.");
  53. /*    
  54.     mView             = ::Q3Object_Duplicate(inOriginal.mView);
  55.     ThrowIfNil_(mView);
  56.     mModel            = ::Q3Shared_GetReference(inOriginal.mModel);
  57.     mInterpolation    = ::Q3Shared_GetReference(inOriginal.mInterpolation);
  58.     mBackFacing        = ::Q3Shared_GetReference(inOriginal.mBackFacing);
  59.     mFillStyle         = ::Q3Shared_GetReference(inOriginal.mFillStyle);
  60. */
  61. }
  62.     
  63. CQD3DPane::CQD3DPane(LStream *inStream)    : LPane(inStream),
  64.     mView(0), mModel(0), mInterpolation(0), mBackFacing(0), mFillStyle(0),
  65.       mLights(0), mCamera(0), mDrawContext(0), mRenderer(0), mDefaultAttributes(0)
  66. {    // stream constructor
  67.     // Does nothing. QD3D Objects are built when needed.
  68.     // (That's one way to make it exception safe.)
  69. }
  70.     
  71. CQD3DPane::~CQD3DPane()
  72. {    // destructor
  73.     
  74.     Q3Forget( mFillStyle );
  75.     Q3Forget( mBackFacing );
  76.     Q3Forget( mInterpolation );
  77.     Q3Forget( mLights );
  78.     Q3Forget( mCamera );
  79.     Q3Forget( mDrawContext );
  80.     Q3Forget( mRenderer );
  81.     Q3Forget( mModel );
  82.     Q3Forget( mView );
  83.     Q3Forget( mDefaultAttributes );
  84. }
  85.  
  86. void    CQD3DPane::RebuildView()
  87. {
  88.     Q3Forget( mView );
  89. }
  90.  
  91. void CQD3DPane::ResizeFrameBy(
  92.     Int16        inWidthDelta,
  93.     Int16        inHeightDelta,
  94.     Boolean        inRefresh)
  95. {
  96.     LPane::ResizeFrameBy( inWidthDelta, inHeightDelta, inRefresh );
  97.     
  98.     // We need to adjust the Q3View to fit the new pane size
  99.     AdjustQ3ViewToFrame();
  100. }
  101.  
  102. void CQD3DPane::MoveBy(
  103.     Int32        inHorizDelta,
  104.     Int32        inVertDelta,
  105.     Boolean        inRefresh)
  106. {
  107.     LPane::ResizeFrameBy( inHorizDelta, inVertDelta, inRefresh );
  108.     
  109.     // We need to adjust the Q3View to fit the new pane size
  110.     AdjustQ3ViewToFrame();
  111. }
  112.  
  113. void CQD3DPane::AdjustQ3ViewToFrame()
  114. {
  115.     // Adjust the camera to fit the pane size
  116.     if ( GetCamera() && ::Q3Camera_GetType(GetCamera()) == kQ3CameraTypeViewAngleAspect ) {
  117.     
  118.         SDimension16 frameSize;
  119.         GetFrameSize( frameSize );
  120.         
  121.         Assert_( frameSize.width > 0 && frameSize.height > 0 );
  122.         float aspect = (float) (frameSize.width) / (float) (frameSize.height);
  123.         
  124.         TQ3Status status = ::Q3ViewAngleAspectCamera_SetAspectRatio( GetCamera(), aspect );
  125.         ThrowIfQ3Fail_( status );
  126.         
  127.     }
  128.     
  129.     // Adjust the draw context to fit the pane size
  130.     if ( GetDrawContext() != nil ) {
  131.         
  132.         Rect frame;
  133.         CalcLocalFrameRect( frame );
  134.         
  135.         TQ3Area pane;
  136.         ::Q3Point2D_Set( &pane.min, frame.left, frame.top );
  137.         ::Q3Point2D_Set( &pane.max, frame.right, frame.bottom );
  138.         
  139.         TQ3Status status = ::Q3DrawContext_SetPane( GetDrawContext(), &pane );
  140.         ThrowIfQ3Fail_( status );
  141.     }
  142. }
  143.  
  144. #pragma mark === Object Getters ===
  145.  
  146. TQ3StyleObject    CQD3DPane::GetInterpolation()
  147. {
  148.     if (mInterpolation==0)
  149.         mInterpolation = ::Q3InterpolationStyle_New( GetInterpolationStyle() ) ;
  150.     
  151.     ThrowIfNil_( mInterpolation );
  152.     return mInterpolation;
  153. }
  154.  
  155. TQ3StyleObject    CQD3DPane::GetBackFacing()
  156. {
  157.     if (mBackFacing==0)
  158.         mBackFacing = ::Q3BackfacingStyle_New( GetBackfacingStyle() ) ;
  159.     
  160.     ThrowIfNil_( mBackFacing );
  161.     return mBackFacing;
  162. }
  163.  
  164. TQ3StyleObject    CQD3DPane::GetFill()
  165. {
  166.     if (mFillStyle==0)
  167.         mFillStyle = ::Q3FillStyle_New( GetFillStyle() ) ;
  168.     
  169.     ThrowIfNil_( mFillStyle );
  170.     return mFillStyle;
  171. }
  172.  
  173. TQ3DrawContextObject CQD3DPane::GetDrawContext(void)
  174. {
  175.     if ( mDrawContext == nil ) {
  176.     
  177.         Rect theFrame;
  178.         CalcLocalFrameRect( theFrame );
  179.         
  180.         CDrawContextMaker maker( (CGrafPtr) GetMacPort(), theFrame );
  181.         mDrawContext = maker.GetRef();
  182.         
  183.     }
  184.     
  185.     return mDrawContext;
  186. }
  187.  
  188. void    CQD3DPane::SetClearImageColor(const TQ3ColorARGB &inColor)
  189. {
  190.     TQ3DrawContextObject theContext = GetDrawContext();
  191.     Assert_(theContext != nil);
  192.     TQ3Status theStatus = ::Q3DrawContext_SetClearImageColor(theContext,&inColor);
  193.     Assert_(theStatus == kQ3Success);
  194. }
  195.  
  196. void    CQD3DPane::GetClearImageColor(TQ3ColorARGB &outColor)
  197. {
  198.     TQ3DrawContextObject theContext = GetDrawContext();
  199.     Assert_(theContext != nil);
  200.     TQ3Status theStatus = ::Q3DrawContext_GetClearImageColor(theContext,&outColor);
  201.     Assert_(theStatus == kQ3Success);
  202. }
  203.  
  204. void    CQD3DPane::SetRenderer(TQ3RendererObject inRenderer)
  205. {
  206.     Assert_( inRenderer != nil );
  207.     
  208.     Q3Forget(mRenderer);
  209.     RebuildView();    // forces the view to be rebuilt
  210.     
  211.     mRenderer = ::Q3Shared_GetReference( inRenderer );
  212. }
  213.  
  214. TQ3RendererObject CQD3DPane::GetRenderer(void)
  215. {
  216.     if ( mRenderer == nil ) {
  217.         CRendererMaker maker;
  218.         mRenderer = maker.GetRef();
  219.     }
  220.     
  221.     return mRenderer;
  222. }
  223.  
  224. void    CQD3DPane::SetModel( TQ3GroupObject inGroup )
  225. {
  226.     Assert_( inGroup != nil );
  227.     
  228.     Q3Forget( mModel );
  229.     RebuildView();    // forces the view to be rebuilt
  230.     
  231.     mModel = ::Q3Shared_GetReference( inGroup );
  232. }
  233.  
  234. TQ3GroupObject    CQD3DPane::GetModel(void)
  235. {
  236.     if ( mModel == nil ) {
  237.         // No model was supplied. Make something to look at.
  238.         CBoxMaker maker;
  239.         
  240.         // Make a group to put it in
  241.         mModel = ::Q3DisplayGroup_New();
  242.         ThrowIfNil_(mModel);
  243.         
  244.         TQ3GroupPosition    pos;
  245.         pos = ::Q3Group_AddObject( mModel, maker.Get() );
  246.         ThrowIf_(pos==0);
  247.                 
  248.     }
  249.     
  250.     return mModel;
  251. }
  252.  
  253. void    CQD3DPane::SetCamera( TQ3CameraObject inCamera )
  254. {
  255.     Assert_( inCamera != nil );
  256.     
  257.     Q3Forget( mCamera );
  258.     RebuildView();    // forces the view to be rebuilt
  259.     
  260.     mCamera = ::Q3Shared_GetReference( inCamera );
  261.     
  262.     // Adjust the camera to the size of the pane.
  263.     AdjustQ3ViewToFrame();
  264. }
  265.  
  266. TQ3CameraObject    CQD3DPane::GetCamera(void)
  267. {
  268.     if ( mCamera == nil ) {
  269.         // No camera was supplied. Make something to see with.
  270.         SDimension16 theSize;
  271.         GetFrameSize( theSize );
  272.         
  273.         CCameraMaker maker( theSize );
  274.  
  275.         mCamera = maker.GetRef();
  276.     }
  277.     
  278.     return mCamera;
  279. }
  280.  
  281. void    CQD3DPane::SetLights( TQ3GroupObject inLights )
  282. {
  283.     Assert_( inLights != nil );
  284.     
  285.     Q3Forget( mLights );
  286.     RebuildView();    // forces the view to be rebuilt
  287.     
  288.     mLights = ::Q3Shared_GetReference( inLights );
  289. }
  290.  
  291. TQ3GroupObject    CQD3DPane::GetLights(void)
  292. {
  293.     if ( mLights == nil ) {
  294.         // No camera was supplied. Make something to see with.
  295.         
  296.         C3Lights maker;
  297.  
  298.         mLights = maker.GetRef();
  299.     }
  300.     
  301.     return mLights;
  302. }
  303.  
  304. void    CQD3DPane::SetDefaultAttributes(TQ3AttributeSet inAttributes)
  305. {
  306.     Assert_(inAttributes != nil);
  307.     
  308.     Q3Forget(mDefaultAttributes);
  309.     RebuildView();    // forces the view to be rebuilt
  310.     
  311.     mDefaultAttributes = ::Q3Shared_GetReference(inAttributes);
  312. }
  313.  
  314. TQ3AttributeSet CQD3DPane::GetDefaultAttributes(void)
  315. {
  316.     SignalPStr_("\pGetDefaultAttributes() not yet implimented");
  317.     return nil;
  318. }
  319.  
  320. void CQD3DPane::SetViewHints(TQ3ViewHintsObject inHints)
  321. {
  322.     // If there are no hints, ignore them.
  323.     if (inHints == nil) return;
  324.     
  325.     TQ3Status theStatus;
  326.     
  327.     TQ3RendererObject theRenderer;
  328.     theStatus = ::Q3ViewHints_GetRenderer(inHints, &theRenderer);
  329.     if (theStatus == kQ3Success && theRenderer != nil) {
  330.         SetRenderer(theRenderer);
  331.         Q3Forget(theRenderer);
  332.     }
  333.     
  334.     TQ3CameraObject theCamera;
  335.     theStatus = ::Q3ViewHints_GetCamera(inHints, &theCamera);
  336.     // Note: I expected that theStatus would be kQ3Fail if there were no camera
  337.     // but I have a bug report to the contrary. So now I check for theCamera != nil as well.
  338.     if (theStatus == kQ3Success && theCamera != nil) {
  339.         SetCamera(theCamera);
  340.         Q3Forget(theCamera);
  341.     }
  342.     
  343.     TQ3GroupObject theLightGroup;
  344.     theStatus = ::Q3ViewHints_GetLightGroup(inHints, &theLightGroup);
  345.     if (theStatus == kQ3Success && theLightGroup != nil) {
  346.         SetLights(theLightGroup);
  347.         Q3Forget(theLightGroup);
  348.     }
  349.     
  350.     TQ3AttributeSet theAttributes;
  351.     theStatus = ::Q3ViewHints_GetAttributeSet(inHints, &theAttributes);
  352.     if (theStatus == kQ3Success && theAttributes != nil) {
  353.         SetDefaultAttributes(theAttributes);
  354.         Q3Forget(theAttributes);
  355.     }
  356.     
  357.     // For TQ3DrawContext related stuff
  358.     TQ3DrawContextObject theContext = GetDrawContext();
  359.     Assert_(theContext != nil);
  360.     
  361.     TQ3Boolean dimensionsAreValid;
  362.     theStatus = ::Q3ViewHints_GetDimensionsState(inHints, &dimensionsAreValid);
  363.     if (theStatus == kQ3Success) {
  364.     //    SetDimensionsState(isValid);
  365.     }
  366.     
  367.     if (dimensionsAreValid) {
  368.         unsigned long theWidth, theHeight;
  369.         theStatus = ::Q3ViewHints_GetDimensions(inHints, &theWidth, &theHeight);
  370.         if (theStatus == kQ3Success) {
  371.         //    SetDimensions(theWidth, theHeight);
  372.         }
  373.     }
  374.     
  375.     TQ3Boolean maskIsValid;
  376.     theStatus = ::Q3ViewHints_GetMaskState(inHints, &maskIsValid);
  377.     if (theStatus == kQ3Success) {
  378.         theStatus = ::Q3DrawContext_SetMaskState(theContext,maskIsValid);
  379.         Assert_(theStatus == kQ3Success);
  380.     }
  381.     if (maskIsValid) {
  382.         TQ3Bitmap theMask = {0,0,0,0};
  383.         theStatus = ::Q3ViewHints_GetMask(inHints, &theMask);
  384.         if (theStatus == kQ3Success) {
  385.             theStatus = ::Q3DrawContext_SetMask(theContext,&theMask);
  386.             Assert_(theStatus == kQ3Success);
  387.             theStatus = ::Q3Bitmap_Empty( &theMask );
  388.             Assert_(theStatus == kQ3Success);
  389.         }
  390.     }
  391.     
  392.     
  393.     TQ3DrawContextClearImageMethod theMethod;    // ???
  394.     theStatus = ::Q3ViewHints_GetClearImageMethod(inHints, &theMethod);
  395.     if (theStatus == kQ3Success) {
  396.         theStatus = ::Q3DrawContext_SetClearImageMethod(theContext,theMethod);
  397.         Assert_(theStatus == kQ3Success);
  398.     }
  399.     
  400.     TQ3ColorARGB theColor;
  401.     theStatus = ::Q3ViewHints_GetClearImageColor(inHints, &theColor);
  402.     if (theStatus == kQ3Success) {
  403.         SetClearImageColor(theColor);    // Ha! We have a method for that!
  404.     }
  405.     
  406. }
  407.  
  408. TQ3ViewObject CQD3DPane::GetView()
  409. {
  410.     // A View must have a Camera, a Renderer, and a Draw Context.
  411.     // The lights are optional.
  412.     
  413.     TQ3Status status;
  414.     
  415.     if ( mView == 0 ) {
  416.     
  417.         mView = ::Q3View_New();
  418.         ThrowIfNil_(mView);
  419.         
  420.         status = ::Q3View_SetDrawContext(mView, GetDrawContext() );
  421.         ThrowIfQ3Fail_(status);
  422.         
  423.         status = ::Q3View_SetRenderer(mView, GetRenderer() );
  424.         ThrowIfQ3Fail_(status);
  425.         
  426.         status = ::Q3View_SetCamera(mView, GetCamera() );
  427.         ThrowIfQ3Fail_(status);
  428.         
  429.         status = ::Q3View_SetLightGroup(mView, GetLights() );
  430.         ThrowIfQ3Fail_(status);
  431.         
  432.         if (mDefaultAttributes) {
  433.             status = ::Q3View_SetDefaultAttributeSet(mView, mDefaultAttributes);
  434.             ThrowIfQ3Fail_(status);
  435.         }
  436.     }
  437.     
  438.     return mView;
  439. }
  440.  
  441. #pragma mark === Drawing/Submitting ===
  442.  
  443. void CQD3DPane::DrawSelf()
  444. {    // Your basic submitting loop.
  445.     
  446.     // we don't enter the submit loop after a fatal error, 
  447.     // or if we are already submitting something
  448.     if (sSawFatalError) return;    
  449.     if (sNowSubmitting) return;
  450.     StSubmittingSetter theSetter;    // sets sNowSubmitting
  451.     
  452.     TQ3Status        status;
  453.     TQ3ViewStatus    viewStatus;
  454.     status = ::Q3View_StartRendering(GetView());
  455.     ThrowIfQ3Fail_(status);
  456.     try {
  457.         do {
  458.             status = SubmitScene();
  459.             viewStatus = ::Q3View_EndRendering(GetView());
  460.         } while ( viewStatus == kQ3ViewStatusRetraverse );
  461.     }
  462.     catch (...) {
  463.         // if something threw an exception, we need to stop rendering
  464.         status = ::Q3View_Cancel(GetView());
  465.         throw;
  466.     }
  467. }
  468.  
  469. void CQD3DPane::CalcBoundingBox(TQ3BoundingBox &outBox, TQ3ComputeBounds inComputeBounds)
  470. {    // Your basic submitting loop.
  471.     
  472.     Assert_(inComputeBounds==kQ3ComputeBoundsApproximate || inComputeBounds==kQ3ComputeBoundsExact);
  473.     
  474.     // we don't enter the submit loop after a fatal error, 
  475.     // or if we are already submitting something
  476.     if (sSawFatalError) return;    
  477.     if (sNowSubmitting) return;
  478.     StSubmittingSetter theSetter;    // sets sNowSubmitting
  479.     
  480.     TQ3Status        status;
  481.     TQ3ViewStatus    viewStatus;
  482.     status = ::Q3View_StartBoundingBox(GetView(), inComputeBounds);
  483.     ThrowIfQ3Fail_(status);
  484.     try {
  485.         do {
  486.         //    status = SubmitScene();
  487.             status = ::Q3DisplayGroup_Submit( GetModel(), GetView() );
  488.             viewStatus = ::Q3View_EndBoundingBox(GetView(), &outBox);
  489.         } while ( viewStatus == kQ3ViewStatusRetraverse );
  490.     }
  491.     catch (...) {
  492.         // if something threw an exception, we need to stop rendering
  493.         status = ::Q3View_Cancel(GetView());
  494.         throw;
  495.     }
  496. }
  497.  
  498. void CQD3DPane::Write( TQ3FileObject inFile )
  499. {    // Your basic submitting loop.
  500.     // we don't enter the submit loop after a fatal error, 
  501.     // or if we are already submitting something
  502.     if (sSawFatalError) return;    
  503.     if (sNowSubmitting) return;
  504.     StSubmittingSetter theSetter;    // sets sNowSubmitting
  505.     
  506.     TQ3Status        status;
  507.     TQ3ViewStatus    viewStatus;
  508.     status = ::Q3View_StartWriting(GetView(), inFile);
  509.     ThrowIfQ3Fail_(status);
  510.     try {
  511.         do {
  512.             status = SubmitScene();
  513.         //    status = ::Q3DisplayGroup_Submit( GetModel(), GetView() );
  514.             viewStatus = ::Q3View_EndWriting( GetView() );
  515.         } while ( viewStatus == kQ3ViewStatusRetraverse );
  516.     }
  517.     catch (...) {
  518.         // if something threw an exception, we need to stop rendering
  519.         status = ::Q3View_Cancel(GetView());
  520.         throw;
  521.     }
  522. }
  523.  
  524. TQ3Status
  525. CQD3DPane::SubmitScene()
  526. {    // As recommended in develop 23, we separate the body 
  527.     // of the Submit loop so it may be used for other things
  528.     // than rendering.
  529.     TQ3Status status;
  530.     status = ::Q3Style_Submit( GetInterpolation(), GetView() );
  531.     if (status==kQ3Failure) return status;
  532.     
  533.     status = ::Q3Style_Submit( GetBackFacing(), GetView() );
  534.     if (status==kQ3Failure) return status;
  535.     
  536.     status = ::Q3Style_Submit( GetFill(), GetView() );
  537.     if (status==kQ3Failure) return status;
  538.     
  539.     status = ::Q3DisplayGroup_Submit( GetModel(), GetView() );
  540.     return status;
  541. }
  542.  
  543.